SPORE.$Import('core.element.base');

/*
---

name: Element.Style

description: Contains methods for interacting with the styles of Elements in a fashionable way.

license: MIT-style license.

requires: Element

provides: Element.Style

...
*/

SPORE.register('core.element.style',function($ns){

	var html = document.html;
	
	Element.Properties.styles = {set: function(styles){
		this.setStyles(styles);
	}};
	
	var hasOpacity = (html.style.opacity != null);
	var reAlpha = /alpha\(opacity=([\d.]+)\)/i;
	
	var setOpacity = function(element, opacity){
		if (!element.currentStyle || !element.currentStyle.hasLayout) element.style.zoom = 1;
		if (hasOpacity){
			element.style.opacity = opacity;
		} else {
			opacity = (opacity * 100).limit(0, 100).round();
			opacity = (opacity == 100) ? '' : 'alpha(opacity=' + opacity + ')';
			var filter = element.style.filter || element.getComputedStyle('filter') || '';
			element.style.filter = reAlpha.test(filter) ? filter.replace(reAlpha, opacity) : filter + opacity;
		}
	};
	
	Element.Properties.opacity = {
	
		set: function(opacity){
			var visibility = this.style.visibility;
			if (opacity == 0 && visibility != 'hidden') this.style.visibility = 'hidden';
			else if (opacity != 0 && visibility != 'visible') this.style.visibility = 'visible';
	
			setOpacity(this, opacity);
		},
	
		get: (hasOpacity) ? function(){
			var opacity = this.style.opacity || this.getComputedStyle('opacity');
			return (opacity == '') ? 1 : opacity;
		} : function(){
			var opacity, filter = (this.style.filter || this.getComputedStyle('filter'));
			if (filter) opacity = filter.match(reAlpha);
			return (opacity == null || filter == null) ? 1 : (opacity[1] / 100);
		}
	
	};
	
	var floatName = (html.style.cssFloat == null) ? 'styleFloat' : 'cssFloat';
	
	Element.implement({
	
		getComputedStyle: function(property){
			if (this.currentStyle) return this.currentStyle[property.camelCase()];
			var defaultView = Element.getDocument(this).defaultView,
				computed = defaultView ? defaultView.getComputedStyle(this, null) : null;
			return (computed) ? computed.getPropertyValue((property == floatName) ? 'float' : property.hyphenate()) : null;
		},
	
		setOpacity: function(value){
			setOpacity(this, value);
			return this;
		},
	
		getOpacity: function(){
			return this.get('opacity');
		},
	
		setStyle: function(property, value){
			switch (property){
				case 'opacity': return this.set('opacity', parseFloat(value));
				case 'float': property = floatName;
			}
			property = property.camelCase();
			if (typeOf(value) != 'string'){
				var map = (Element.Styles[property] || '@').split(' ');
				value = Array.from(value).map(function(val, i){
					if (!map[i]) return '';
					return (typeOf(val) == 'number') ? map[i].replace('@', Math.round(val)) : val;
				}).join(' ');
			} else if (value == String(Number(value))){
				value = Math.round(value);
			}
			this.style[property] = value;
			return this;
		},
	
		getStyle: function(property){
			switch (property){
				case 'opacity': return this.get('opacity');
				case 'float': property = floatName;
			}
			property = property.camelCase();
			var result = this.style[property];
			if (!result || property == 'zIndex'){
				result = [];
				for (var style in Element.ShortStyles){
					if (property != style) continue;
					for (var s in Element.ShortStyles[style]) result.push(this.getStyle(s));
					return result.join(' ');
				}
				result = this.getComputedStyle(property);
			}
			if (result){
				result = String(result);
				var color = result.match(/rgba?\([\d\s,]+\)/);
				if (color) result = result.replace(color[0], color[0].rgbToHex());
			}
			if (Browser.opera || (Browser.ie && isNaN(parseFloat(result)))){
				if ((/^(height|width)$/).test(property)){
					var values = (property == 'width') ? ['left', 'right'] : ['top', 'bottom'], size = 0;
					values.each(function(value){
						size += this.getStyle('border-' + value + '-width').toInt() + this.getStyle('padding-' + value).toInt();
					}, this);
					return this['offset' + property.capitalize()] - size + 'px';
				}
				if (Browser.opera && String(result).indexOf('px') != -1) return result;
				if ((/^border(.+)Width|margin|padding/).test(property)) return '0px';
			}
			return result;
		},
	
		setStyles: function(styles){
			for (var style in styles) this.setStyle(style, styles[style]);
			return this;
		},
	
		getStyles: function(){
			var result = {};
			Array.flatten(arguments).each(function(key){
				result[key] = this.getStyle(key);
			}, this);
			return result;
		}
	
	});
	
	Element.Styles = {
		left: '@px', top: '@px', bottom: '@px', right: '@px',
		width: '@px', height: '@px', maxWidth: '@px', maxHeight: '@px', minWidth: '@px', minHeight: '@px',
		backgroundColor: 'rgb(@, @, @)', backgroundPosition: '@px @px', color: 'rgb(@, @, @)',
		fontSize: '@px', letterSpacing: '@px', lineHeight: '@px', clip: 'rect(@px @px @px @px)',
		margin: '@px @px @px @px', padding: '@px @px @px @px', border: '@px @ rgb(@, @, @) @px @ rgb(@, @, @) @px @ rgb(@, @, @)',
		borderWidth: '@px @px @px @px', borderStyle: '@ @ @ @', borderColor: 'rgb(@, @, @) rgb(@, @, @) rgb(@, @, @) rgb(@, @, @)',
		zIndex: '@', 'zoom': '@', fontWeight: '@', textIndent: '@px', opacity: '@'
	};
	
	
	
	Element.ShortStyles = {margin: {}, padding: {}, border: {}, borderWidth: {}, borderStyle: {}, borderColor: {}};
	
	['Top', 'Right', 'Bottom', 'Left'].each(function(direction){
		var Short = Element.ShortStyles;
		var All = Element.Styles;
		['margin', 'padding'].each(function(style){
			var sd = style + direction;
			Short[style][sd] = All[sd] = '@px';
		});
		var bd = 'border' + direction;
		Short.border[bd] = All[bd] = '@px @ rgb(@, @, @)';
		var bdw = bd + 'Width', bds = bd + 'Style', bdc = bd + 'Color';
		Short[bd] = {};
		Short.borderWidth[bdw] = Short[bd][bdw] = All[bdw] = '@px';
		Short.borderStyle[bds] = Short[bd][bds] = All[bds] = '@';
		Short.borderColor[bdc] = Short[bd][bdc] = All[bdc] = 'rgb(@, @, @)';
	});

});